package com.jjw.route.talk;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Component
@Slf4j
@ServerEndpoint("/websocket/{username}/{poiName}") //暴露的ws应用的路径
public class WebSocket {

    /** 当前在线客户端数量（线程安全的） */
    private static AtomicInteger onlineClientNumber = new AtomicInteger(0);

    /** 当前在线客户端集合（线程安全的）：以键值对方式存储，key是连接的编号，value是连接的对象 */
    private static Map<String ,Session> onlineClientMap = new ConcurrentHashMap<>();

    /** 当前各个地区的session 信息 */
    private static Map<String, Map<String,Session>> poiOnlineClientMap = new ConcurrentHashMap<>();

    /**
     * 客户端与服务端连接成功
     * @param session
     * @param username
     * @param poiName
     */
    @OnOpen
    public void onOpen(Session session,@PathParam("username") String username,@PathParam("poiName") String poiName){
        /*
            do something for onOpen
            与当前客户端连接成功时
         */
        onlineClientNumber.incrementAndGet();//在线数+1
        onlineClientMap.put(session.getId(),session);//添加当前连接的session

        if (poiOnlineClientMap.containsKey(poiName)) {
            Map<String,Session> sessions = poiOnlineClientMap.get(poiName);
            if (sessions == null) sessions = new ConcurrentHashMap<>();
            sessions.put(session.getId(),session);
        }else{
            Map<String,Session> sessions = new ConcurrentHashMap<>();
            sessions.put(session.getId(),session);
            poiOnlineClientMap.put(poiName,sessions);
        }

        log.info("时间[{}]：与用户[{}]的连接成功，当前连接编号[{}]，当前连接总数[{}]",
                new Date(),
                username,
                session.getId(),
                onlineClientNumber);
        log.info("时间[{}]：与用户[{}]的连接成功，在[{}]中，当前连接编号[{}]，当前连接总数[{}]",
                new Date(),
                username,
                poiName,
                session.getId(),
                onlineClientNumber);
    }

    /**
     * 客户端与服务端连接关闭
     * @param session
     * @param username
     * @param poiName
     */
    @OnClose
    public void onClose(Session session,@PathParam("username") String username,@PathParam("poiName") String poiName){
        /*
            do something for onClose
            与当前客户端连接关闭时
         */
        onlineClientNumber.decrementAndGet();//在线数-1
        onlineClientMap.remove(session.getId());//移除当前连接的session
        Map<String, Session> stringSessionMap = poiOnlineClientMap.get(poiName);
        stringSessionMap.remove(session.getId());
        log.info("时间[{}]：与用户[{}]的连接关闭，当前连接编号[{}]，当前连接总数[{}]",
                new Date(),
                username,
                session.getId(),
                onlineClientNumber);
        log.info("时间[{}]：与用户[{}]连接断开，在[{}]中，当前连接编号[{}]，当前连接总数[{}]",
                new Date(),
                username,
                poiName,
                session.getId(),
                onlineClientNumber);
    }

    /**
     * 客户端与服务端连接异常
     * @param error
     * @param session
     * @param username
     * @param poiName
     */
    @OnError
    public void onError(Throwable error,Session session,@PathParam("username") String username,@PathParam("poiName") String poiName) {
        /*
            do something for onError
            与当前客户端连接异常时
         */
        error.printStackTrace();
    }

    /**
     * 客户端向服务端发送消息
     * @param message
     * @param username
     * @throws IOException
     */
    @OnMessage
    public void onMsg(Session session,String message,@PathParam("username") String username,@PathParam("poiName") String poiName) throws IOException {
        /*
            do something for onMessage
            收到来自当前客户端的消息时
         */
        log.info("时间[{}]：来自连接编号为[{}]的消息：[{}]",
                new Date() ,
                session.getId(),
                message);
//        sendAllMessage(message,session.getId());
        sendALlMessageByPoiName(message,poiName,session.getId());
    }

    //向所有客户端发送消息（广播）
    private void sendAllMessage(String message, String id){
        Set<String> sessionIdSet = onlineClientMap.keySet(); //获得Map的Key的集合
        for (String sessionId : sessionIdSet) { //迭代Key集合
            if (id.equals(sessionId)) continue;
            Session session = onlineClientMap.get(sessionId); //根据Key得到value
            session.getAsyncRemote().sendText(message); //发送消息给客户端
        }
    }

    private void sendALlMessageByPoiName(String message,String poiName,String id) {
        Map<String, Session> stringSessionMap = poiOnlineClientMap.get(poiName);
        Set<String> strings = stringSessionMap.keySet();
        for (String string : strings) {
            if (string.equals(id)) continue;
            stringSessionMap.get(string).getAsyncRemote().sendText(message);
        }
    }
}

